package tdd.demo.demo001;


import static org.junit.Assert.assertEquals;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

/**
 * @author sanwen88  
 * @date 2020年4月16日 上午8:35:48 
 *
 * @Description: 井字游戏案例演示TDD测试驱动开发
 * 	http://www.testclass.net/tdd/
 *
 * 	
 * 	
	   x  |   o  |  x
	------|------|------
	   o  |   o  |  o
	------|------|------
		  |   x  |  x
	------|------|------
		  |      | 
	
 */
public class TicTacToeTest {
	
	@Rule
	public ExpectedException exception = ExpectedException.none();
	
	private TicTacToe ticTacToe;
	
	@Before
	public final void init() {
		this.ticTacToe = new TicTacToe();
	}
	
	/************************************需求一单元测试*********************************/
	/*
		 需求一：先定义边界，以及将棋子放在哪些地方非法。
	
		可将棋子放在3×3棋盘上任何没有棋子的地方。
	
		将需求分成三个测试：
	
		如果棋子放在超出了X轴边界的地方，就引发 RuntimeException 异常。
		如果棋子放在超出了Y轴边界的地方，就引发 RuntimeException 异常。
		如果棋子放在已经有棋子的地方，就引发 RuntimeException 异常。
	 */
	/*
	 * 	测试X轴超出边界
	 */
	@Test
	public void whenXOutsideBoardThenRuntimeException() {
		exception.expect(RuntimeException.class);
		ticTacToe.play(5, 2);
	}
	
	/*
	 * 	测试Y轴超出边界
	 */
	@Test
	public void whenYOutsideBoardThenRuntimeException() {
		exception.expect(RuntimeException.class);
		ticTacToe.play(3, 5);
	}
	
	/*
	 * 	测试坐标被占用
	 */
	@Test
	public void whenOccupiedThenRuntimeException() {
		ticTacToe.play(2, 1);
		exception.expect(RuntimeException.class);
		ticTacToe.play(2, 1);
	}
	
	/************************************需求二单元测试*********************************/
	/*
		 需求二：现在处理轮到哪个玩家落子问题。
	
		需要提供一种途径，用于判断接下来该谁落子。
	
		将需求分成三个测试：
	
		玩家 X 先下；
		如果上一次是 X 下的，接下来将轮到 O 下。
		如果上一次是 O 下的，接下来将轮到 X 下。
	 */
	//确保返回一个玩家即为通过，不管是谁先落子
	@Test
	public void givenFirstTurnWhenNextPlayerThenX() {
		assertEquals('X', ticTacToe.nextPlayer());
	}
	
	/*
	 * 	确保玩家轮流落子。
	 * 	如果前一次是玩家 X 下的，接下来应该轮到玩家 O
	 * 	去实现代码。
	 */
	
	@Test
	public void givenLastTurnWasXWhenNextPlayerThenO() {
		ticTacToe.play(1, 1);
		assertEquals('O', ticTacToe.nextPlayer());
	}
	
	/*
	 * 	如果前一次是玩家 O 下的，接下来应该是玩家 X 下。
	 */
	@Test
	public void givenLastTurnWasXWhenNextPlayerThenX(){
		ticTacToe.play(1,1);
	    ticTacToe.play(1,2);
	    assertEquals('X', ticTacToe.nextPlayer());
	}
	
	/************************************需求三单元测试*********************************/
	/*
	 	现在考虑这个游戏的获胜规则，这部分工作会比较麻烦。我们必须检查所可能获胜的情况，只要满足其中一个，就宣布相应玩家获胜。
		最先在水平、锤直或对角线上将自己的3个标记连起来的玩家获胜。
	 */
	//首先定义play() 的默认返回值 - 无人获胜
	@Test
	public void whenPlayThenNoWinner() {
		String actual = ticTacToe.play(1,1);
	    assertEquals("No winner", actual);
	}
	
	//处理各种获胜条件。
	/*
	 * 	测试场景：X 玩家最新占满一条垂直线，所以 X 玩家获胜。
	 * 	去代码实现
	 */
	@Test
	public void whenPlayAndWholeHorizontalLineThenWinner() {
		ticTacToe.play(1,1);  //X
		ticTacToe.play(1, 2); //O
		ticTacToe.play(2,1);  //X
	    ticTacToe.play(2,2);  //O
	    String actual = ticTacToe.play(3, 1); //X
	    assertEquals("X is the winner", actual);
	}
	/*
	 * 	测试场景：一个玩家（O）的棋子占据整条水平线就赢了。
	 * 	去代码实现
	 */
	@Test
	public void whenPlayAndWholeVerticalLineThenWinner(){
		ticTacToe.play(1,1);  //O
	    ticTacToe.play(2,1);  //X
	    ticTacToe.play(3,1);  //X
	    ticTacToe.play(1,2);  //O
	    ticTacToe.play(2,2);  //O
	    String actual = ticTacToe.play(1,3);  //O
	    assertEquals("O is the winner", actual);
	}
	/*
	 * 	测试场景： 水平线和垂直线都搞定后，最后来实现对角线 - \。
	 * 	去代码实现
	 */
	@Test
	public void whenPlayAndTopBottomDiagonalLineThenWinner(){
	    ticTacToe.play(1,1);  //X
	    ticTacToe.play(1,2);  //O
	    ticTacToe.play(2,2);  //X
	    ticTacToe.play(1,3);  //O
	    String actual = ticTacToe.play(3,3); //X
	    assertEquals("X is the winner", actual);
	}
	/*
	 * 	测试场景： 水平线和垂直线都搞定后，最后来实现对角线 - /。
	 * 	去代码实现
	 */
	@Test
	public void whenPlayAndBottomTopDiagonalLineThenWinner(){
	    ticTacToe.play(1,3);  //X
	    ticTacToe.play(1,1);  //O
	    ticTacToe.play(2,2);  //X
	    ticTacToe.play(1,2);  //O
	    String actual = ticTacToe.play(3,1); //X
	    assertEquals("X is the winner", actual);
	}
	
	/************************************需求四单元测试*********************************/
	/*
	 * 	所有格子都占满则为平局。
	 */
	@Test
	public void whenAllBoxesAreFilledThenDraw(){
	    ticTacToe.play(1,1);  //X
	    ticTacToe.play(1,2);  //O
	    ticTacToe.play(1,3);  //X
	    ticTacToe.play(2,1);  //O
	    ticTacToe.play(2,3);  //X
	    ticTacToe.play(2,2);  //O
	    ticTacToe.play(3,1);  //X
	    ticTacToe.play(3,3);  //O
	    String actual = ticTacToe.play(3,2); //X
	    assertEquals("The result is draw", actual);
	}
	
	
	
}
